package com.cm.kits;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.management.ManagementFactory;
import java.net.Inet4Address;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;

/**
 * 系统环境信息处理工具
 *
 * @author LWang 2023.01.19
 * @since 1.0.0
 */
@Slf4j
public final class EnvironmentToolkit {
    private EnvironmentToolkit() {
    }

    /**
     * 本机 IP 信息，防止重复获取
     */
    private static volatile String LOCAL_IP;

    private static volatile String MAC;

    private static volatile List<Integer> LOCAL_IP_VALUES;

    private static final String UNKNOWN = "unknown";

    private static final String COMMA = ",";


    private static synchronized void getIpInfos() {
        if (StringUtils.isBlank(LOCAL_IP) || Objects.isNull(LOCAL_IP_VALUES) || LOCAL_IP_VALUES.isEmpty()) {
            try {
                final var ipSet = new HashSet<String>();
                final var macSet = new HashSet<>();
                LOCAL_IP_VALUES = new ArrayList<>();
                NetworkInterface
                        .getNetworkInterfaces()
                        .asIterator()
                        .forEachRemaining(networkInterface -> {
                            try {
                                if (networkInterface.isUp() && !networkInterface.isLoopback() && !networkInterface.isVirtual()) {
                                    networkInterface
                                            .getInetAddresses()
                                            .asIterator()
                                            .forEachRemaining(inetAddress -> {
                                                if (inetAddress instanceof Inet4Address) {
                                                    ipSet.add(inetAddress.getHostAddress());
                                                    byte[] ipAddress = inetAddress.getAddress();
                                                    LOCAL_IP_VALUES.add((ipAddress[0] << 24) & (ipAddress[1] << 16) & (ipAddress[2] << 8) & ipAddress[3]);
                                                }
                                            });
                                    var hardwareAddress = networkInterface.getHardwareAddress();
                                    if (ArrayUtils.isNotEmpty(hardwareAddress)) {
                                        macSet.add(HashKits.toHex(hardwareAddress));
                                    }
                                }
                            } catch (SocketException ex) {
                                log.error("获取本机 IP 地址发生异常：", ex);
                            }
                        });
                LOCAL_IP = StringUtils.join(ipSet, COMMA);
                MAC = StringUtils.join(macSet, COMMA);
            } catch (SocketException e) {
                log.error("获取本机 IP 地址发生异常：", e);
            }
        }
    }

    /**
     * 获取本机 IP
     * 返回结果忽略本地回环地址（127.0.0.1），localhost 和 IPv6 地址，如果是明确的虚拟网卡也忽略
     *
     * @return 本机 IP（多个 IP 使用 "," 连接）
     */
    public static String getLocalIp() {
        if (StringUtils.isBlank(LOCAL_IP)) {
            getIpInfos();
        }
        return LOCAL_IP;
    }

    /**
     * 获取本机 MAC 地址
     *
     * @return 本机 MAC（多个 MAC 使用 "," 连接）
     */
    public static String getMac() {
        if (StringUtils.isBlank(MAC)) {
            getIpInfos();
        }
        return MAC;
    }


    /**
     * 获取本机 IP 值
     * 返回结果忽略本地回环地址（127.0.0.1），localhost 和 IPv6 地址，如果是明确的虚拟网卡也忽略
     *
     * @return 整型列表，IP 地址的 int 表示
     */
    public static List<Integer> getLocalIpValue() {
        if (Objects.isNull(LOCAL_IP_VALUES) || LOCAL_IP_VALUES.isEmpty()) {
            getIpInfos();
        }
        return LOCAL_IP_VALUES;
    }

    /**
     * 获取当前进程 ID
     *
     * @return 当前进程 ID
     */
    public static long getProcessId() {
        return ManagementFactory.getRuntimeMXBean().getPid();
    }
}
